package org.example.service.impl;

import cn.dev33.satoken.secure.SaSecureUtil;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.exceptions.ValidateException;
import cn.hutool.core.lang.Assert;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import org.example.dao.TUserAuthDao;
import org.example.dto.UserAdminDTO;
import org.example.dto.UserAreaDTO;
import org.example.dto.UserLogoutStatusDTO;
import org.example.entity.TUserAuth;
import org.example.entity.TUserInfo;
import org.example.param.UserAuthParam;
import org.example.result.UserAuthResult;
import org.example.service.RedisService;
import org.example.service.TUserAuthService;
import org.example.service.TUserInfoService;
import org.example.utils.PageUtils;
import org.example.vo.ConditionVO;
import org.example.vo.PageResult;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

import static org.example.constant.RedisPrefixConst.USER_AREA;
import static org.example.constant.RedisPrefixConst.VISITOR_AREA;
import static org.example.enums.UserAreaTypeEnum.getUserAreaType;


/**
 * (TUserAuth)表服务实现类
 *
 * @author makejava
 * @since 2023-06-14 14:09:38
 */
@Service("tUserAuthService")
@RequiredArgsConstructor
public class TUserAuthServiceImpl extends ServiceImpl<TUserAuthDao, TUserAuth> implements TUserAuthService {
    private final TUserInfoService tUserInfoService;
    /**
     * redis
     * */
    private final RedisService redisService;
    /**
     * userAuthDao
     * */
    private final TUserAuthDao tUserAuthDao;


    @Value("${sa-token.key}")
    private String key;


    /**
     * 注册
     *
     * @param userAuthParam 参数
     * @return 注册结果
     */
    @Override
    public UserAuthResult register(UserAuthParam userAuthParam) {
        //创建用户信息
        TUserInfo tUserInfo = new TUserInfo();
        //创建账号密码
        TUserAuth tUserAuth = new TUserAuth();
        BeanUtils.copyProperties(userAuthParam, tUserInfo);
        BeanUtils.copyProperties(userAuthParam, tUserAuth);
        //判断数据库中是否存在账号
        Boolean aBoolean = authUserName(tUserAuth);
        if (aBoolean) {
            throw new ValidateException("用户名已存在");
        }
        tUserInfoService.save(tUserInfo);
        tUserAuth.setUserInfoId(tUserInfo.getId());
        //密码加密
        tUserAuth.setPassword(
                SaSecureUtil.aesEncrypt(key, tUserAuth.getPassword())
        );
        this.save(tUserAuth);
        UserAuthResult userAuthResult = new UserAuthResult();
        BeanUtils.copyProperties(tUserInfo, userAuthResult);
        return userAuthResult;
    }

    private Boolean authUserName(TUserAuth tUserAuth) {
        return count(new LambdaQueryWrapper<TUserAuth>().eq(TUserAuth::getUsername, tUserAuth.getUsername())) > 0;
    }

    /**
     * @param userAuthParam 登录参数
     * @return UserAuthResult res
     */
    @Override
    public UserAuthResult login(UserAuthParam userAuthParam) {
        TUserAuth tUserAuth = new TUserAuth();
        BeanUtils.copyProperties(userAuthParam, tUserAuth);
        //查询用户信息
        TUserAuth one = this.getOne(new LambdaQueryWrapper<TUserAuth>().eq(TUserAuth::getUsername, tUserAuth.getUsername()));
        Assert.notNull(one, "账号不存在");
        //密码解密
        Assert.isTrue(
                SaSecureUtil
                        .aesDecrypt(
                                key,
                                one.getPassword()
                        )
                        .equals(tUserAuth.getPassword())
                ,
                "{}密码不正确"
                , one.getUsername()
        );
        TUserInfo tUserInfo = tUserInfoService.getById(one.getUserInfoId());
        //校验成功 进行登录
        StpUtil.login(one.getUsername());
        //查询token
        String tokenValue = StpUtil.getTokenValue();
        UserAuthResult userAuthResult = new UserAuthResult();
        BeanUtils.copyProperties(tUserInfo,userAuthResult);
        BeanUtils.copyProperties(tUserAuth,userAuthResult);
        userAuthResult.setToken(tokenValue);
        return userAuthResult;
    }
    @Override
    public List<UserAreaDTO> listUserAreas(ConditionVO conditionVO) {
        List<UserAreaDTO> userAreaDTOs = new ArrayList<>();
        switch (Objects.requireNonNull(getUserAreaType(conditionVO.getType()))) {
            case USER:
                // 查询注册用户区域分布
                Object userArea = redisService.get(USER_AREA);
                if (Objects.nonNull(userArea)) {
                    userAreaDTOs = JSON.parseObject(userArea.toString(), List.class);
                }
                return userAreaDTOs;
            case VISITOR:
                // 查询游客区域分布
                Map<String, Object> visitorArea = redisService.hGetAll(VISITOR_AREA);
                if (Objects.nonNull(visitorArea)) {
                    userAreaDTOs = visitorArea.entrySet().stream()
                            .map(item -> UserAreaDTO.builder()
                                    .name(item.getKey())
                                    .value(Long.valueOf(item.getValue().toString()))
                                    .build())
                            .collect(Collectors.toList());
                }
                return userAreaDTOs;
            default:
                break;
        }
        return userAreaDTOs;
    }

    @Override
    public PageResult<UserAdminDTO> listUsers(ConditionVO conditionVO) {
        // 获取后台用户数量
        Integer count = tUserAuthDao.countUser(conditionVO);
        if (count == 0) {
            return new PageResult<>();
        }
        // 获取后台用户列表
        List<UserAdminDTO> userAdminDtoS = tUserAuthDao.listUsers(PageUtils.getLimitCurrent(), PageUtils.getSize(), conditionVO);
        return new PageResult<>(userAdminDtoS, count);
    }

    /**
     * 登出
     *
     * @return UserLogoutStatusDTO
     */
    @Override
    public UserLogoutStatusDTO logout() {
        StpUtil.logout();
        return new UserLogoutStatusDTO("注销成功");
    }
}
